// 条件表达式类型
// L extends R ? X : Y;
// L: 左操作数(Source)
// R: 右操作数(Target)
// X: True 分支
// Y: False 分支
// 如果类型 L可以赋值给类型 R，则结果为 X，否则为 Y

// 条件类型: 类型检查
type L = 'abc'
type R = string
type T = L extends R ? true : false

// 示例，从映射中去除签名
type T1 = {
    [k: string]: string | number 
    a: string
    b: number
    c: 1
}

// 从 T1 中去除字符串索引签名，去掉 [k: string] 
// keyof T1 是 'a' | 'b' | 'c' | string
type T2 = {
    // in 右边的 keyof 不会发生合并操作
    [k in keyof T1 as (
        string extends k ? never : k
    )]: T1[k]
}
// 从 T1 中去除字符串索引签名, 
// 但此时的 keyof T1 已经发生了合并
// 过滤掉 string类型的key
type T21 = Exclude<keyof T1, string>

// 两种语义(基础类型, 注意交换L/R与交换X/Y式不同的)
type Is<T, target> = T extends target ? 'true' : 'false'
type Equal<T, target> = target extends T ? Is<T, target> : 'false'
type C1 = Is<'abc', string> // 'true'
type C2 = Equal<string, string> // 'true'

// 非裸类型参数
type U1 = 'a' | 'b' | 'c'
type X<T> = T // 可以表达 'abc', string
type XN1 = `${U1}`
type XN2 = U1[]
type XN3 = [U1]
type XN4 = X<U1>
type XN5 = Promise<U1>

// 两种特殊的"裸类型参数(naked type parameter)"
// - 作为"泛型参数"传入
// - 以"裸类型参数"的形式参与extends左侧运算
type U = 'a' | 2
type X1 = Is<U, string> // X1 结果集合可能性有三种可能: X, Y, X|Y
type X2 = Is<never, string> // 结果 never

// any是特殊的(boolean与enum并不特殊，它们都是按联合来处理的)
type X3 = Is<any, false>
type X31 = any extends false ? 'true' : 'false'
type X4 = Is<boolean, true>
type X41 = boolean extends true ? 'true': 'false'
enum E {a,b,c}
type X5 = Is<E, 1>
type X51 = E extends 1 ? 'true' : 'false'




// 当 T是一个联合类型（Union Type），并且条件类型写在形式 [T] extends [U] ? X : Y的“裸”形式
// （即 T不是包裹在元组或其它类型中）时，TypeScript 会将条件类型自动分配（distribute）到联合类型的每一个成员上。
// 换句话说：
// T extends U ? X : Y   // 当 T 是联合类型时(其中 T = T1 | T2 | T3 | ...)，会分布到每个成员上
// 等价于：
// T1 extends U ? X : Y
// | T2 extends U ? X : Y
// | T3 extends U ? X : Y
// ...

// 结果是：true
// never extends T总是返回 true，所以条件类型的结果总是取 ?前面的部分（即 X）
// never是​​最底层、最小的类型​​，它可以被认为是任何类型的子类型（空集是任何集合的子集）。
// 所以 never extends T​​永远为 true​​，不管 T是什么类型。
// 因此：never extends string ? ... : ...的结果永远是 true分支。
type Test = never extends string ? true : false;
